package com.excilys.capicsoubank.entities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;

import org.apache.commons.lang3.ObjectUtils;

/**
 * POJO Account.
 * 
 * @author Tiphaine Ruy
 * 
 */
@Entity
@Table(name = "ACCOUNT")
public class Account implements Serializable {

	private static final long serialVersionUID = -5640334605781435947L;
	private Integer accountId;
	private User user;
	private List<Transaction> transactions = new ArrayList<Transaction>();
	private String label;
	private long balance;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "account_id", unique = true, nullable = false)
	public Integer getAccountId() {
		return this.accountId;
	}

	public void setAccountId(Integer accountId) {
		this.accountId = accountId;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "user_id", nullable = false)
	public User getUser() {
		return this.user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	@OneToMany(cascade = CascadeType.ALL, mappedBy = "account")
	@OrderBy("date DESC")
	public List<Transaction> getTransactions() {
		return this.transactions;
	}

	public void setTransactions(List<Transaction> transactions) {
		this.transactions = transactions;
	}

	@Column(name = "label", nullable = false, length = 45)
	public String getLabel() {
		return this.label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	@Column(name = "balance", nullable = false)
	public long getBalance() {
		return this.balance;
	}

	public void setBalance(long balance) {
		this.balance = balance;
	}

	/**
	 * Ajoute un montant relatif au solde du compte.
	 * 
	 * @param amount
	 *            Le montant
	 */
	public void addAmountToBalance(long amount) {
		this.balance += amount;
	}

	@Override
	public String toString() {
		return "Account [accountId=" + accountId + ", user=" + user
				+ ", label=" + label + ", balance=" + balance + "]";
	}

	@Override
	public int hashCode() {
		return accountId;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;

		if (obj == null)
			return false;

		if (getClass() != obj.getClass())
			return false;

		Account account = (Account) obj;

		return ObjectUtils.equals(accountId, account.getAccountId());
	}

	/**
	 * Builder de la classe Account.
	 * 
	 * @author "Grégory Coutant"
	 * 
	 */
	public static class Builder {
		private final Account account = new Account();

		/**
		 * Builder pour l'attribut user.
		 * 
		 * @param user
		 *            Le user
		 * @return Le Builder
		 */
		public Builder user(User user) {
			account.user = user;
			return this;
		}

		/**
		 * Builder pour l'attribut accountId.
		 * 
		 * @param accountId
		 *            L'ID du compte
		 * @return Le Builder
		 */
		public Builder accountId(Integer accountId) {
			account.accountId = accountId;
			return this;
		}

		/**
		 * Builder pour l'attribut label.
		 * 
		 * @param label
		 *            Le label du compte
		 * @return Le Builder
		 */
		public Builder label(String label) {
			account.label = label;
			return this;
		}

		/**
		 * Builder pour l'attribut balance.
		 * 
		 * @param balance
		 *            Le solde du compte
		 * @return Le Builder
		 */
		public Builder balance(long balance) {
			account.balance = balance;
			return this;
		}

		/**
		 * Construit le compte.
		 * 
		 * @return Le compte
		 */
		public Account build() {
			return account;
		}
	}
}
